<?php
/**
 * Form builder class. Tool to build form using description in a XML files 
 * ('FORMS_FILES' constant should be defined by path to these XML configs files) or 
 * it could build forms without any config
 * 
 * @author Konstantin Shamko <konstantin.shamko@gmail.com> 
 * @version 0.0.1
 * @copyright  Copyright (c) 2009 Konstantin Shamko
 * @category VaselinEngine
 * @package Bel Classes
 * @license  New BSD License
 *
 */
class Bel_Forms_Builder {	
	
	/**
	 * Form action
	 *
	 * @var string
	 */
	public $_action;
		
	/**
	 * Form method (POST or GET)
	 *
	 * @var string
	 */
	public $_method;
		
	/**
	 * Array of form fields
	 *
	 * @var array
	 */
	public $_fields;
		
	/**
	 * Form name
	 *
	 * @var string
	 */
	public $_formname = null;
		
	/**
	 * Constructor. Sets form action, name & method. If XML config file was found 
	 * adds fields to form according to this file
	 *
	 * @param string $formname - form name
	 * @param string $action - form action
	 * @param string $method - form method
	 * 
	 * @return void
	 */
	public function __construct($formname, $action = null, $method = 'POST') {
		
		$this->_formname = $formname;
		$this->_method = $method;
		
		if (file_exists ( FORMS_FILES . $formname . '.xml' )) {
			$xml_obj = simplexml_load_file ( FORMS_FILES . $formname . '.xml' );
			
			foreach ( $xml_obj->fields->field as $field ) {
				$fld = ( array ) $field;
				$this->addElement ( $fld ['type'], $fld ['name'], $fld );
			}
		}
		
		if ($action) {
			$this->_action = $action;
		}
	}	
	
	/**
	 * Sets form action
	 *
	 * @param string $action
	 * 
	 * @return void
	 */
	public function setAction($action) {
		$this->_action = $action;
	}	
	
	/**
	 * Sets form method
	 *
	 * @param string $method
	 * 
	 * @return void
	 */
	public function setMethod($method) {
		$this->_method = $method;
	}	
	
	/**
	 * Adds element to form
	 *
	 * @param string $type - element type (i.e. text, textarea, select etc.)
	 * @param string $name - name of element
	 * @param array $options - associative array with additional element params
	 * 
	 * @return void
	 */
	public function addElement($type, $name, $options = null) {
		$this->_fields [$name] ['type'] = $type;
		$this->_fields [$name] ['name'] = $name;

		if (is_array ( $options )) {
			foreach ( $options as $key => $val ) {
				if($key=='options'){					
					$_options = array();//
					if(($opts = $val->option)){
						foreach ($opts as $opt){
							$_options[(string)$opt->attributes()->value] = (string)$opt;
						}							
					}
					$this->addSubElement($name,'options',$_options);					
				}else{
					$this->_fields [$name] [$key] = $val;
				}
			}
		}
	}	
	
	/**
	 * Adds attributes to elements that are in form
	 *
	 * @param string $name - name of element
	 * @param array $attributes - associative array with additional element params
	 * 
	 * @return void
	 */
	public function addAttributes($name, $attributes) {
		$form_fields = array_keys ( $this->_fields );
		
		foreach ( $attributes as $key => $val ) {
			if (in_array ( $name, $form_fields ))
				$this->_fields [$name] [$key] = $val;
		}
	}	
	
	/**
	 * Transforms form from object to array
	 *
	 * @return array
	 */
	public function toArray() {
		return ( array ) $this;
	}
	
	/**
	 * Removes element from form
	 *
	 * @param string $name - element name
	 * 
	 * @return Bel_Forms_Builder
	 */
	public function removeElement($name) {
		unset ( $this->_fields [$name] );
		return $this;
	}
		
	/**
	 * Gets an element.
	 *
	 * @param string $name - element name
	 * @param string $offset - subelement name
	 * @return array - array with element data
	 */
	public function getElement($name, $offset = NULL) {
		if (! isset ( $this->_fields [$name] ))
			return false;
		return ($offset) ? $this->_fields [$name] [$offset] : $this->_fields [$name];
	}	
	
	/**
	 * Adds subelement. (i.e. add options into select)
	 *
	 * @param string $parent_element - parent element name
	 * @param string $element_type - subelement type
	 * @param array $new_element - associative array with additional subelement params
	 * 
	 * @return void
	 */
	public function addSubElement($parent_element, $element_type, $new_element) {
		$this->_fields [$parent_element] [$element_type] [] = $new_element;
	}	
	
	/**
	 * Populates form with values
	 *
	 * @param array $form_data - associative array with form elements values. Keys - form elements' names, values - form elements' values
	 * 
	 * @return void
	 */
	public function populateForm($form_data) {	
		foreach ( $form_data as $key => $val ) {			
			if ($this->getElement ( $key )) {				
				$type = $this->getElement ( $key, 'type' );				
				
				switch ( $type) {					
					case 'checkbox' :
						$attributes ['value'] = 1;
						if (( int ) $val == 1) {
							$attributes ['checked'] = $val;
						} else
							unset ( $attributes ['checked'] );
					break;
					
					case 'select' :
						$name = $this->getElement ( $key, 'name' );						
						if (is_array ( $form_data [$name] )) {
							$selected = array ( );
							foreach ( $form_data [$name] as $fld ) {
								$selected [] = $fld;
							}
						} else {
							$selected = $form_data [$name];
						}						
						$this->_fields [$name] ['selected'] = $selected;					
					break;
					
					default :
						$attributes ['value'] = $val;
					break;
				}				
				$this->addAttributes ( $key, $attributes );
			}
		}
	}
}